package client

import (
	"gitee.com/Cookie_XiaoD/go-terminalserver/protocol/std808core/body"
	"gitee.com/Cookie_XiaoD/go-terminalserver/protocol/std808core/body/downbody"
	"gitee.com/Cookie_XiaoD/go-terminalserver/protocol/std808core/body/upbody"
	"gitee.com/Cookie_XiaoD/go-terminalserver/protocol/std808core/msg"
	"gitee.com/Cookie_XiaoD/go-terminalserver/util"
	"log"
	"net"
)

//TerminalClient 终端客户端
type TerminalClient struct {
	//终端实际的TcpClient
	client *net.TCPConn
	//客户端远程终结点
	remoteAddr string
	//终端号（鉴权后才有）
	terminalCode string
	//接收到且未处理前的所有数据
	allDatas []byte
	//终端客户端对应的终端信息
	terminalInfo *terminalModel
	//平台应答消息流水号 从0开始
	sn uint16
	//标记当前终端是否通过了鉴权
	passAuth bool
}

//终端客户端对应的终端信息
type terminalModel struct {
	//终端SIM卡号
	terminalSim string
	//终端内部车牌号(理论上，终端内部车牌号与实际车辆车牌应该一致）
	plateNo string
	//终端号
	terminalCode string
	//17位车架号
	vin string
}

func NewTerminalClient(conn *net.TCPConn) *TerminalClient {
	if conn == nil {
		return nil
	}
	addr := conn.RemoteAddr().String()
	return &TerminalClient{
		client:       conn,
		remoteAddr:   addr,
		terminalCode: "",
		//标识位1+消息头16+消息体（1023)+校验位1+标识位1  共1042个字节，
		//考虑可能的转义，极端情况下消息头、消息体、校验位的每一个字节都需要转义的话，
		//16+1023+1的数量翻倍为2080
		//最后为2082
		allDatas: make([]byte, 0, 2080),
	}

}

func (tc *TerminalClient) StartHandleUpData() {
	//client.SetReadBuffer(readBufSize)
	defer func() {
		if tc.client != nil {
			log.Printf("%v连接断开", tc.remoteAddr)
			//TODO:从字典中移除失效客户端
			tc.client.Close()
		}
	}()

	readBuffer := make([]byte, 2080)
	//接收终端上行数据,当终端鉴权成功后，根据终端号添加到字典中
	for {
		readLen, err := tc.client.Read(readBuffer)
		if err != nil {
			break
		}
		//针对TCP，需要处理粘包等问题，收到的数据默认全部放到缓存中
		tc.allDatas = append(tc.allDatas, readBuffer[0:readLen]...)
		datas := util.ProcessStickPackage(msg.FlagByte, msg.FlagByte, &tc.allDatas)
		for _, v := range datas {
			tc.handleMsg(v)
		}
	}
}

func (tc *TerminalClient) handleMsg(msgBytes []byte) {
	//协议标记头和尾不需要做反转义处理
	tmpMsg := util.ReverseEscapeBytes(msgBytes, msg.FlagByte, 0x7d, 0x02, 0x01)
	//log.Println(tmpMsg)
	revMsg, err := msg.Unpack(tmpMsg)
	if err != nil {
		return
	}
	if !revMsg.PassCheck {
		log.Println("消息校验位不正确")
		return
	}
	if tc.passAuth {
		tc.handleMsgAfterAuth(revMsg)
		return
	}
	tc.handleMsgBeforeAuth(revMsg)

}

//handleMsgAfterAuth 处理鉴权成功之后的消息
func (tc *TerminalClient) handleMsgAfterAuth(revMsg *msg.Std808Msg) {
	switch revMsg.MessageID {
	case msg.TerminalHeart:
		log.Println("接收到终端心跳")
		//终端心跳 进行通用应答
		tc.sendGeneralResp(revMsg, body.GR_SuccessOrConfirm)
	case msg.TerminalLocation:
		log.Println("接收到终端定位")
		tc.handleLocation(revMsg)
	}
}

//handleMsgBeforeAuth 处理鉴权成功之前的消息
func (tc *TerminalClient) handleMsgBeforeAuth(revMsg *msg.Std808Msg) {
	switch revMsg.MessageID {
	case msg.TerminalReg:
		log.Println("接收到终端注册")
		tc.handleReg(revMsg)
	case msg.TerminalAuth:
		log.Println("接收到终端鉴权")
		tc.handleAuth(revMsg)
	}
}

//handleLocation 处理终端定位上报
func (tc *TerminalClient) handleLocation(revMsg *msg.Std808Msg) {
	locData := upbody.AyalyseLocation(revMsg)
	if locData == nil {
		tc.sendGeneralMsgErrorResp(revMsg)
		return
	}
	log.Println(util.Bytes2HexString(revMsg.MessageBody))

	//TODO:解析定位数据，丢入定位消息处理管道
	tc.sendGeneralResp(revMsg, body.GR_SuccessOrConfirm)
}

func (tc *TerminalClient) handleReg(revMsg *msg.Std808Msg) {
	regData := upbody.AnalyseReg(revMsg)
	if regData == nil {
		return
	}
	//TODO：需要比较 终端号与车牌号的关系，这里暂时默认为成功
	//情况1：终端号 车牌号均匹配，则注册成功
	//情况2：终端号匹配，车牌号不匹配，则终端已注册
	//情况3：终端号不匹配，车牌号存在匹配数据，则 车辆已被注册
	//情况4：终端号不匹配 车牌号不匹配，则数据库中无该终端
	//数据库中无该车辆暂时无匹配场景
	tc.terminalInfo = &terminalModel{
		terminalSim:  revMsg.TerminalSIM,
		terminalCode: regData.TerminalID,
		plateNo:      regData.VehicleID,
		vin:          "", //TODO:需要更改为从缓存获取
	}

	result := body.RegResult_Success
	//鉴权码直接用终端号
	respBody := downbody.NewTerminalRegRespBody(revMsg.SerialNumber, result, regData.TerminalID)
	tc.sendResp(respBody, revMsg, msg.RegResp)
}

func (tc *TerminalClient) handleAuth(revMsg *msg.Std808Msg) {
	authData := upbody.AnalyseAuth(revMsg)
	if authData == nil {
		tc.sendGeneralMsgErrorResp(revMsg)
		return
	}
	//比较鉴权码是否正确，鉴权码就是终端号
	//TODO:从缓存中根据终端号匹配终端信息，之类默认成功

	result := body.GR_SuccessOrConfirm
	tc.passAuth = true
	tc.sendGeneralResp(revMsg, result)
}

func (tc *TerminalClient) sendGeneralMsgErrorResp(revMsg *msg.Std808Msg) {
	body := downbody.NewGeneralRespBody(revMsg.SerialNumber, revMsg.MessageID, body.GR_MSG_ERROR)
	tc.sendResp(body, revMsg, msg.GeneralResp)
}

func (tc *TerminalClient) sendGeneralResp(revMsg *msg.Std808Msg, result body.PlatformGeneralRespResult) {
	body := downbody.NewGeneralRespBody(revMsg.SerialNumber, revMsg.MessageID, result)
	tc.sendResp(body, revMsg, msg.GeneralResp)
}

func (tc *TerminalClient) sendResp(body body.To808BytesConverter, revMsg *msg.Std808Msg, msgid msg.Std808PlateformMsgID) {
	plateMsg := msg.NewPlateformBasicMessage(msgid, false, revMsg.TerminalSIM, tc.getSN(), nil, body)
	msgBytes, err := msg.Pack(plateMsg)
	if err != nil {
		log.Printf("平台消息%v打包异常：%v", msgid, err.Error())
		return
	}
	log.Printf("平台消息：%v[%v]", msgid, util.Bytes2HexString(msgBytes))
	tc.WriteBytes(msgBytes)
}

func (tc *TerminalClient) WriteBytes(bytes []byte) {
	len, err := tc.client.Write(bytes)
	if err != nil {
		log.Printf("发送数据到客户端异常：%v", err.Error())
		return
	}
	log.Printf("发送数据成功，共%v个字节", len)
}

func (tc *TerminalClient) getSN() uint16 {
	sn := tc.sn
	tc.sn = tc.sn + 1
	return sn
}
